#include "StdAfx.h"
#include "MarkupEX.h"

/*static*/ u32 GetStringValue(LPCTSTR val_str)
{
	u32 value=0;
	bool negative=false;

	if(val_str[0]=='-') {negative=true; val_str++;}

	// hexadecimal
	if(_tcsnccmp(val_str,_T("0x"),2)==0)
		_stscanf(val_str,_T("0x%x"),&value);
	// alternate hex
	else if(val_str[0]==_T('$'))
		_stscanf(val_str,_T("$%x"),&value);
	// binary
	else if(_tcsnccmp(val_str,_T("0b"),2)==0)
	{
		// convert
		while(val_str[2]!=NULL)
		{
			value<<=1;
			if(val_str[2]=='1') value|=1;
			val_str++;
		}
	}
	// octal
	else if(_tcsnccmp(val_str,_T("0o"),2)==0)
		_stscanf(val_str,_T("0o%o"),&value);
	// html rgb
	else if(val_str[0]==_T('#'))
		_stscanf(val_str,_T("#%x"),&value);
	// must be decimal
	else _stscanf(val_str,_T("%d"),&value);

	// take into account negative transformation
	if(negative) value=~value;

	return value;
}

/*static*/ GString SetStringValue(u32 value, CMarkupEX::ValueType type)
{
	GString val_str;

	switch(type)
	{
		case CMarkupEX::VALTYPE_HEX:
			val_str.Format(_T("0x%x"),value); break;
		case CMarkupEX::VALTYPE_OCT:
			val_str.Format(_T("0o%o"),value); break;
		case CMarkupEX::VALTYPE_RGB:
			val_str.Format(_T("#%.6x"),value); break;
		case CMarkupEX::VALTYPE_ASM:
			val_str.Format(_T("$%x"),value); break;
		case CMarkupEX::VALTYPE_DEC:
			val_str.Format(_T("%d"),value); break;
		case CMarkupEX::VALTYPE_BIN:
			val_str=_T("0b");
			if(value==0) val_str+=_T('0');
			else
			{
				u32 i, mask;
				// mask out zeroes
				for(i=0, mask=0x80000000; i<32; i++, mask>>=1)
					if(value&mask) break;
				// create string now
				for(; i<32; i++, mask>>=1)
				{
					if(value&mask) val_str+=_T('1');
					else val_str+=_T('0');
				}
			}
			break;
	}

	return val_str;
}

inline static u32 GetXmlVal(CMarkup *xml, LPCTSTR name)
{
	return GetStringValue(xml->GetChildAttrib(name));
}

inline static u32 GetXmlChildVal(CMarkup *xml, LPCTSTR name)
{
	return GetStringValue(xml->GetChildAttrib(name));
}

CMarkupEX::CMarkupEX(void)
{
}

CMarkupEX::~CMarkupEX(void)
{
}

void CMarkupEX::AddValue(LPCTSTR name, u32 value, ValueType type)
{
	GString str=SetStringValue(value,type);
	this->AddElem(name);
	this->AddAttrib(_T("val"),str);
}

u32 CMarkupEX::GetValue(LPCTSTR name)
{
	if(FindChildElem(name))
		return GetXmlVal(this,_T("val"));
	return -1;
}

void CMarkupEX::SetValue(LPCTSTR name, u32 value, ValueType type)
{
	GString str=SetStringValue(value,type);
	this->SetAttrib(name,str);
}

void CMarkupEX::SetChildValue(LPCTSTR name, u32 value, ValueType type)
{
	GString str=SetStringValue(value,type);
	this->SetChildAttrib(name,str);
}

int CMarkupEX::Open(LPCTSTR file_name)
{
	TCHAR* buffer=NULL;

	if(StoreUtf8Text(file_name,buffer))
	{
		SetDoc(buffer);

		// success
		if(buffer) delete[] buffer; return 1;
	}

	// failed
	if(buffer) delete[] buffer; return 0;
}

int CMarkupEX::Save(LPCTSTR file_name)
{
	FILE *out=_tfopen(file_name,_T("wb+"));

	if(!out) return 0;

	WriteBOM(out);
	WriteUtf8(GetDoc(),out);
	fclose(out);

	return 1;
}
